package mark.tom.fiter;

import android.app.Activity;
import android.content.Context;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.io.IOException;
import java.lang.ref.WeakReference;

import mark.tom.fiter.bean.AggregateBean;
import mark.tom.fiter.bean.ResolvedAggregateBean;
import mark.tom.fiter.bean.config.OkHttpConfig;
import mark.tom.fiter.bean.config.RequestConfig;
import mark.tom.fiter.constants.StatusCodeEnums;
import mark.tom.fiter.http.ssl.NoneSSLSocketFactory;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import static java.net.HttpURLConnection.HTTP_OK;
import static mark.tom.fiter.constants.StatusCodeConstants.CONNECT_ERROR_CODE;

public final class BuzDispatcher implements ResponseDispatcher {

    private static final BuzDispatcher ourInstance = new BuzDispatcher();

    public static BuzDispatcher getInstance() {
        return ourInstance;
    }

    private ResponseResolver resolver;
    private ProcessConverter converter;
    private NetErrorInterceptor netInterceptor;

    private BuzDispatcher() {
        this(new Buz.Builder()
                .converter(new ConverterFactory().get())
                .resolver(new ResolverFactory().get())
                .okHttpConfig(new OkHttpConfig().setSslSocketFactory(NoneSSLSocketFactory.getHttpSSLSocketFactory()))
                .build());
    }

    private BuzDispatcher(@NonNull Buz buz) {
        updateBuz(buz);
    }

    public void updateBuz(@NonNull Buz buz) {
        if (null != buz.getResolver()) {
            this.resolver = buz.getResolver();
        }
        if (null != buz.getConverter()) {
            this.converter = buz.getConverter();
        }
        if (null != buz.getNetErrorInterceptor()) {
            this.netInterceptor = buz.getNetErrorInterceptor();
        }
        OkHttpClientProvider.getInstance().initOkHttpConfig(buz.getOkHttpConfig());
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T executeRequest(@NonNull Request mRequest, @Nullable RequestConfig mRequestConfig) {
        String responseStr = null;
        byte[] responseByte = null;
        // response 类型
        int responseType = RequestConfig.RESPONSE_STRING;
        if (null != mRequestConfig) {
            responseType = mRequestConfig.getResponseType();
        }
        try {
            Response response = getClient().newCall(mRequest).execute();
            if (null != response && response.isSuccessful()) {
                switch (responseType) {
                    case RequestConfig.RESPONSE_STRING: {
                        responseStr = response.body().string();
                        break;
                    }
                    case RequestConfig.RESPONSE_BYTE: {
                        responseByte = response.body().bytes();
                        break;
                    }
                    default: {
                        break;
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        if (null != responseByte) {
            return (T) responseByte;
        }
        if (TextUtils.isEmpty(responseStr)) {
            return null;
        }
        // 2. 进行数据转换 封装了FastJson解析工作
        Class<?> clazz = null;
        if (null != mRequestConfig) {
            clazz = mRequestConfig.getClazz();
        }
        AggregateBean aggregate = new AggregateBean();
        if (null != resolver) {
            aggregate = resolver.resolve(responseStr, clazz);
        }
        aggregate.setResponse(responseStr);
        aggregate.setRequestConfig(mRequestConfig);
        // 3. 进行数据对象转换 DTO -> BO
        AbstractDTOConverter<?, ?> dtoConverter = null;
        if (null != mRequestConfig) {
            dtoConverter = mRequestConfig.getDtoConverter();
        }
        if (null != dtoConverter) {
            aggregate = dtoConverter.convert(aggregate);
        }
        if (aggregate instanceof ResolvedAggregateBean) {
            ResolvedAggregateBean resolvedAggregate = (ResolvedAggregateBean) aggregate;
            return (T) resolvedAggregate.getData();
        }
        return null;
    }

    @Override
    public void executeRequest(@NonNull Context mContext,
                               @NonNull Request mRequest,
                               @Nullable RequestConfig mRequestConfig,
                               @Nullable IRequestListener<?> mRequestListener) {
        // 如果Activity已关闭则停止请求
        if (mContext instanceof Activity && ((Activity) mContext).isFinishing()) {
            return;
        }
        getClient().newCall(mRequest)
                .enqueue(new JTCallBack(mContext, mRequestConfig,
                        resolver, converter, netInterceptor, mRequestListener));
    }

    private final static class JTCallBack implements Callback {

        private final WeakReference<Context> mContextReference;
        private final IRequestListener<?> mRequestListener;
        private final RequestConfig mRequestConfig;
        private final ResponseResolver mResolver;
        private final ProcessConverter mConverter;
        private final NetErrorInterceptor netInterceptor;

        public JTCallBack(Context mContext,
                          RequestConfig mRequestConfig,
                          @Nullable ResponseResolver mResolver,
                          @Nullable ProcessConverter mConverter,
                          @Nullable NetErrorInterceptor netInterceptor,
                          IRequestListener<?> mRequestListener) {
            this.mContextReference = new WeakReference<>(mContext);
            this.mRequestConfig = mRequestConfig;
            this.mResolver = mResolver;
            this.mConverter = mConverter;
            this.netInterceptor = netInterceptor;
            this.mRequestListener = mRequestListener;
        }

        @Override
        public void onFailure(@NonNull Call call, @NonNull IOException e) {
            if (stopGoon()) {
                return;
            }
            notifyFail(mContextReference.get(), e.getMessage(), CONNECT_ERROR_CODE, mRequestListener);
        }

        @Override
        public void onResponse(@NonNull Call call, @NonNull Response response) {
            if (stopGoon()) {
                return;
            }
            // 请求失败
            if (!response.isSuccessful()) {
                notifyFail(mContextReference.get(), response.message(), HTTP_OK, mRequestListener);
                return;
            }
            // response 类型
            int responseType = RequestConfig.RESPONSE_STRING;
            if (null != mRequestConfig) {
                responseType = mRequestConfig.getResponseType();
            }
            // 直接返回byte[]
            if (RequestConfig.RESPONSE_BYTE == responseType) {
                if (null == mConverter) {
                    return;
                }
                byte[] result = null;
                // 向上层返回成功数据
                try {
                    result = response.body().bytes();
                } catch (Exception ex) {
                    // Ignore
                }
                mConverter.convert(mContextReference.get(), result, mRequestListener);
                return;
            }
            // 1. 读取response中的字符串
            String responseStr = null;
            if (null != response.body()) {
                try {
                    responseStr = response.body().string();
                } catch (Exception ex) {
                    // Ignore
                }
            }
            // 2. 进行数据转换 封装了FastJson解析工作
            Class<?> clazz = null;
            if (null != mRequestConfig) {
                clazz = mRequestConfig.getClazz();
            }
            AggregateBean aggregate = new AggregateBean();
            if (null != mResolver) {
                aggregate = mResolver.resolve(responseStr, clazz);
            }
            aggregate.setResponse(responseStr);
            aggregate.setRequestConfig(mRequestConfig);
            // 3. 进行数据对象转换 DTO -> BO
            AbstractDTOConverter<?, ?> dtoConverter = null;
            if (null != mRequestConfig) {
                dtoConverter = mRequestConfig.getDtoConverter();
            }
            if (null != dtoConverter) {
                aggregate = dtoConverter.convert(aggregate);
            }
            // 4. 向上层返回成功数据
            if (null == mConverter) {
                return;
            }
            mConverter.convert(mContextReference.get(), aggregate, mRequestListener);
        }

        private void notifyFail(@Nullable Context mContext,
                                @Nullable String mMsg,
                                @StatusCodeEnums int errCode,
                                @NonNull IRequestListener<?> mRequestListener) {
            // 网络错误拦截器
            if (null != netInterceptor) {
                netInterceptor.handle(errCode, mMsg, null);
            }
            // 事件分发器
            if (null == mConverter) {
                return;
            }
            mConverter.convert(mContext, mMsg, errCode, mRequestListener);
        }


        private boolean stopGoon() {
            return null == mContextReference.get()
                    || (mContextReference.get() instanceof Activity && ((Activity) mContextReference.get()).isFinishing())
                    || null == mRequestListener;
        }
    }

    private OkHttpClient getClient() {
        return OkHttpClientProvider.getInstance().getOkHttpClient();
    }

}
